;***********************;******************
;Gnomoria_Enhanced.au3 by Billy 'bvierra' Vierra
;Created with ISN AutoIt Studio v. 0.8 BETA
;*****************************************

#Region - _getKingdomNameFromSav
; #FUNCTION# ====================================================================================================================
; Name...........: _getKingdomNameFromSav
; Description ...: Returns the Kingdom Name from a Gnomoria sav file
; Syntax.........: _getKingdomNameFromSav($sFile)
; Parameters ....: $sFile - String of the full path and filename to the Gnomoria sav file
; Return values .: Success - String of the Kingdom name
;				   Failure - 0 and Set @ERROR to:
;				   	|1 - File could not be opened
;					|2 - Could not determine Kingdom Name
; ===============================================================================================================================
Func _getKingdomNameFromSav($sFile)
	Local $f = FileOpen($sFile, 16)
	if $f = -1 Then
		warn("Could not open save file: " & $sFile)
		SetError(1)
		Return(0)
	EndIf
	Local $Read = FileRead($f, 100) ; Read only the 1st 100 bytes of the file
	FileClose($f)
	
	Local $Result = StringTrimLeft($Read, 12)
	Local $ReadByte = StringLeft($Result, 2)
	Local $kingdomName = '0x' & StringLeft($Result, $ReadByte * 10)
	$kingdomName = String(BinaryToString($kingdomName))
	$ret = StringRegExp($kingdomName, '(.*)\W', 2)
	If $ret = '' Then
		SetError(2)
		Return(0)
	EndIf
	Return $return[1]
EndFunc ;==>_getKingdomNameFromSav
#EndRegion

#Region - _runGnomoria
; #FUNCTION# ====================================================================================================================
; Name...........: _runGnomoria
; Description ...: Runs gnomoria and returns the PID
; Syntax.........: _runGnomoria
; Parameters ....:
; Return values .: Success - Process Handle
;				   Failure - 0 and Set @ERROR to:
;				   	|1 - Gnomoria.exe not found
;					|2 - Gnomoria is already running
; ===============================================================================================================================
Func _runGnomoria()
	info("Starting Gnomoria")
	Local $gnomoriaExec = $gnomoriaDirectory & "\Gnomoria.exe"
	If FileExists($gnomoriaExec) = -1 Then ; Make sure the exec exists
		warn("Cannot locate Gnomoria executable at: " $gnomoriaExec)
		SetError(1)
		Return(0)
	ElseIf ProcessExists($gnomoriaProcessName) Then ; Will not run multiple copies of Gnomoria at the same time
		warn("Gnomoria is already running, will not open a second copy")
		SetError(2)
		Return(0)
	EndIf
	If FileExists($gnomoriaLogFile) Then
		FileMove($gnomoriaLogFile, $gnomoriaLogFile & ".bak", 1) ; Move Gnomoria.log to Gnomoria.log.bak overwriting .bak if it exists
	EndIf
	FileChangeDir($gnomoriaDirectory) ; Change working dir to Gnomoria's directory to keep Gnomoria happy
	Local $iPID = Run($gnomoriaExec, $gnomoriaDirectory)
	$gnomoriaRunning = 1
	Return($iPID)
EndFunc ;==>_runGnomoria
#EndRegion

#Region - _gnomoriaCrash
; #FUNCTION# ====================================================================================================================
; Name...........: _gnomoriaCrash()
; Description ...: Called after Gnomoria has crashed and will submit crash log
; Syntax.........: _gnomoriaCrash
; Parameters ....:
; Return values .: Success - String what it returns
;				   Failure - 0 and Set @ERROR to:
;				   	|1 -
;					|2 -
; ===============================================================================================================================
Func _gnomoriaCrash()
	Local $crashDate, $crashVersion, $crashWorld, $crashMessage, $savFile
	Local $crashInfo = _crashReadLog()
	info("A crash was detected from Gnomoria. Sending crash summary to dev team")
	If $crashInfo = 0 Then ;If return was error and not an array then return
		warn("Parsing crash log failed with error code " & @error & " cannot continue")
		Return(0)
	EndIf
	$crashDate = $crashInfo[0]
	$crashVersion = $crashInfo[1]
	$crashWorld = $crashInfo[2]
	$crashMessage = $crashInfo[3]
	;debug("Crash Message: " & $crashMessage)
	$savFile = $savesPath & "\world" & $crashWorld & ".sav"
	If FileExists($savFile) = -1 Then ; If there is no save file for the crash then return
		warn("Save file does not exist, cannot continue")
		Return(0)
	EndIf
	Local $timeDiff = _checkSavTimeDiff($savFile)
	; TODO Send info to server to see if we need more info
	; version | message | timediff
	Local $params = "message=" & _URLEncode($crashMessage) & "&version=" & _URLEncode($crashVersion) & "&timeDiff=" & _URLEncode($timeDiff)
	Local $sData = _apiCall($geApiUrl & "/crash/report",$params)
	If @error Then
		Return 1
	EndIf
	Global $gnomoriaCrash_crashKey,$gnomoriaCrash_upload
	;_parseJson("gnomoriaCrash",$sData)
	;BLEH
	Local $txt = BinaryToString($sData)
	Local $array = StringSplit ( $txt, ",",1)
	Local $i = 1
	While $i <= UBound($array) - 1
		Local $a = StringSplit($array[$i],":")
		$key = StringRegExpReplace($a[1],'\W',"")
		$key = String($key)
		Local $val = StringRegExpReplace($a[2],'[^\w|^\-]',"")
		$val = String($val)
		If $key = "upload" Then
			$gnomoriaCrash_upload = $val
		ElseIf $key = "crashKey" Then
			$gnomoriaCrash_crashKey = $val
		EndIf
		$i = $i + 1
	WEnd
	;BLEH
	debug("[upload] " & $gnomoriaCrash_upload)
	debug("[crashKey] " & $gnomoriaCrash_crashKey)
	If $gnomoriaCrash_upload = 0 Then
		; Server is not looking for more saves
		info("No further information is needed. Thank you!")
		Return 1
	EndIf
	info("Dev Team is requesting full crash log, please wait...");
	Local $tmpZipDir = $tmpDir & "\" & $gnomoriaCrash_crashKey
	debug("Temp Zip Dir: " & $tmpZipDir)
	DirCreate($tmpDir)
	DirRemove($tmpZipDir,1)
	DirCreate($tmpZipDir)
	FileCopy($savFile,$tmpZipDir & "\world" & $crashWorld & ".sav")
	FileCopy($gnomoriaLogFile,$tmpZipDir & "\Gnomoria.log")
	debug("Creating zip @ " & $tmpDir & "\" & $gnomoriaCrash_crashKey & ".zip")
	Local $Zip = _Zip_Create($tmpDir & "\" & $gnomoriaCrash_crashKey & ".zip")
	debug("Add Folder")
	_Zip_AddFolder($Zip,$tmpZipDir)
	DirRemove($tmpZipDir,1)
	debug("Uploading File")
	Local $socket = _HTTPConnect('ge.gnomoriawiki.com', 80)
	Local $uploadData[1], $uploadFiles[1]
	$uploadData[0] = _HTTPEncodeString( "uuid=" & $gnomoriaCrash_crashKey )
	$uploadFiles[0] = $tmpDir & "\" & $gnomoriaCrash_crashKey & ".zip"
	Local $ret = _HTTPPost_files('ge.gnomoriawiki.com','/api/crash/upload',$socket,$uploadData,$uploadFiles)
	debug("Return Code: " & $ret)
	debug("Upload: " & _HTTPRead($socket))
	_HTTPClose($socket)
	FileDelete($tmpDir & "\" & $gnomoriaCrash_crashKey & ".zip")
	info("Full Crash Log has been sent to dev team. Thank you!")
EndFunc ;==>_gnomoriaCrash
#EndRegion

#Region - _crashReadLog
; #FUNCTION# ====================================================================================================================
; Name...........: _crashReadLog
; Description ...: Reads and parses the crash log
; Syntax.........: _crashReadLog()
; Parameters ....:
; Return values .: Success - Array(
;					|String 	Date and Time of crash in local TZ (6/26/2012 8:45:13 PM)
;					|String 	Gnomoria Version (0.8.2.1)
;					|Int		World Number (01)
;					|Straing 	Description of the crash as report by Gnomoria (Object reference not set to an instance of an object.)
;				   )
;				   Failure - 0 and Set @ERROR to:
;				   	|1 - Crash log could not be found
;					|2 - Crash log could not be opened
;					|3 - Could not read line from crashlog (Extended error contains the FileReadLine error)
;					|4 - Crash log finished parsing however not all needed variables were set
; ===============================================================================================================================
Func _crashReadLog()
	debug("Opening up crash log @ " & $gnomoriaLogFile)
	Local $crashDate, $crashVersion, $crashWorld, $crashMessage
	If FileExists($gnomoriaLogFile) = -1 Then
		error("Could not find crash log at: " & $gnomoriaLogFile)
		SetError(1)
		Return(0)
	EndIf
	Local $fh_errorLog = FileOpen($gnomoriaLogFile)
	If $fh_errorLog = -1 Then
		error("Found log file but was unable to open it at: " & $gnomoriaLogFile)
		SetError(2)
		Return(0)
	EndIf
	
	Local $lineCheck = "date"
	While 1
		Local $l = FileReadLine($fh_errorLog)
		If @error Then
			If @error = -1 Then	
				SetError(0)
				ExitLoop
			EndIf
			Local $readError = @error
			error("Received error from while reading Gnomoria.log. Error Code: " & @error)
			SetError(3,$readError)
			ExitLoop
		EndIf
		Local $return
		If $lineCheck = "date" Then
			$return = StringRegExp($l, 'Date:\s(.*)', 3)
			For $i = 0 To UBound($return) - 1
				If StringLen($return[$i]) > 0 Then
					debug("Date: " & $return[$i])
					$crashDate = $return[$i]
					$lineCheck = "version"
				EndIf
			Next
		ElseIf $lineCheck = "version" Then
			$return = StringRegExp($l, 'Version:\s(.*)', 3)
			For $i = 0 To UBound($return) - 1
				If StringLen($return[$i]) > 0 Then
					debug("Version: " & $return[$i])
					$crashVersion = $return[$i]
					$lineCheck = "world"
				EndIf
			Next
		ElseIf $lineCheck = "world" Then
			$return = StringRegExp($l, 'World:\sworld(\d{2})', 3)
			For $i = 0 To UBound($return) - 1
				If StringLen($return[$i]) > 0 Then
					debug("World: " & $return[$i])
					$crashWorld = $return[$i]
					$lineCheck = "message"
				EndIf
			Next
		ElseIf $lineCheck = "message" Then
			$return = StringRegExp($l, 'Message:\s(.*)', 3)
			For $i = 0 To UBound($return) - 1
				If StringLen($return[$i]) > 0 Then
					debug("Message: " & $return[$i])
					$crashMessage = $return[$i]
					$lineCheck = "end"
				EndIf
			Next
		EndIf
	WEnd
	FileClose($fh_errorLog)
	If @error Then
		Return(0)
	EndIf
	If $lineCheck <> "end" Then
		warn("There was an issue parsing log file, cannot continue with crash log")
		debug(" * Date: " & $crashDate)
		debug(" * Version: " & $crashVersion)
		debug(" * World: " & $crashWorld)
		debug(" * Message: " & $crashMessage)
		SetError(4)
		Return(0)
	EndIf
	Local $crashReturn[4] = [$crashDate, $crashVersion, $crashWorld, $crashMessage]
	Return($crashReturn)
EndFunc ;==>_crashReadLog
#EndRegion

#Region - _checkSavTimeDiff
; #FUNCTION# ====================================================================================================================
; Name...........: _checkSavTimeDiff
; Description ...: Returns the difference from sav file and now in minutes
; Syntax.........: _checkSavTimeDiff($sSavFile)
; Parameters ....: $sSavFile - String Full path of Gnomoria save file
; Return values .: Success - Int Difference in min
; ===============================================================================================================================
Func _checkSavTimeDiff($sSavFile)
   Local $n_Fdate = FileGetTime($sSavFile,1)
   Local $timeWorld = $n_Fdate[0] & "/" & $n_Fdate[1] & "/" & $n_Fdate[2] & " "  &  $n_Fdate[3] & ":" & $n_Fdate[4] & ":" & $n_Fdate[5]
   Local $timeNow = _NowCalc()
   Local $timeDiff = _DateDiff ('n',$timeWorld,$timeNow)
   debug("Difference between last save and now is " & $timeDiff & " min")
   Return($timeDiff)
EndFunc ;==>_checkSavTimeDiff
#EndRegion